<?php
/**
 * This file is part of Swoft.
 *
 * @link https://swoft.org
 * @document https://doc.swoft.org
 * @contact group@swoft.org
 * @license https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Controllers;

use Swoft\Http\Server\Bean\Annotation\Controller;
use Swoft\Http\Message\Bean\Annotation\Middleware;
use Swoft\Http\Message\Bean\Annotation\Middlewares;
use Swoft\Http\Server\Bean\Annotation\RequestMapping;
use Swoft\Http\Server\Bean\Annotation\RequestMethod;
// use Swoft\View\Bean\Annotation\View;
// use Swoft\Http\Message\Server\Response;
use App\Middlewares\MerchantSubmitMiddleware;
use App\Middlewares\MerchantSearchMiddleware;
use App\Middlewares\ActionTestMiddleware;
use Swoft\Http\Message\Server\Request;
use App\Models\Entity\MUserapi;
use Swoft\Db\Db;
use Swoft\Db\Query;
use Swoft\App;
// use Swoft\Log\Log;
use Swoft\Task\Task;


/**
 * Class MerchantController
 * @Controller(prefix="/merchant")
 * @package App\Controllers
 */
class MerchantController
{
    /**
     * this is a example action. access uri path: /merchant
     * @RequestMapping(route="/merchant[/]")
     * @Middleware(ActionTestMiddleware::class)
     * @return mixed
     */
    public function index(Request $request)
    {
        // $a = Db::query("SELECT * from m_userapi where userid = :userid", ['userid' => 123])->getResult();
        $log = ['msg' => '测试天天大王拉阿拉蕾', 'data' => ['hello', 'world']];
        \Jpay\Helper\wk_monolog($log);
        return 'ok';
    }

    /**
     * 商户订单提交
     * @RequestMapping(route="submit[/]")
     * @Middleware(MerchantSubmitMiddleware::class)
     * @return array
     */
    public function submit(Request $request): array
    {
        $now = date('Y-m-d H:i:s');

        $inputData = $request->input();

        // 解析运营商、省份
        $corp = base64_decode(str_replace(' ','+', $inputData['corp']));
        if (empty($corp)) $corp = $inputData['corp'];
        $province = base64_decode(str_replace(' ','+', $inputData['province']));
        if (empty($province)) $province = $inputData['province'];
        // 针对内蒙古、黑龙江特殊处理
        // $province = substr($province, 0, 6);
        $province = mb_substr($province, 0, 2, 'UTF-8');

        $ip = $request->getHeaderLine('X-Real-IP');

        $user = $this->validateIpAndSign($inputData, $ip, 'submit');

        $cstatus = 0;
        if (!$user['backopen'] || empty($user['backurl'])) {
            $cstatus = -1;
        }

        $merchantConfig = \config('merchant');

        // 获取相关表
        $tables = \Jpay\Helper\get_shop_table($inputData['shoptype']);
        if (empty($tables)) {
            throw new \Exception('shoptype非法', 501);
        }

        // 查询订单是否已存在 防重提
        // $order = Db::query("SELECT id,account,parvalue,inprice,status,cstatus,bid,qdprice,addtime from {$tables['orderTable']} where userid=:userid and orderid=:orderid limit 1", ['userid' => $inputData['userid'], 'orderid' => $inputData['orderid']])->getResult();
        $order = Db::query("(SELECT id,account,parvalue,operators,inprice,status,cstatus,bid,qdprice,addtime from o_realtime where userid=:userid and orderid=:orderid limit 1) union all (SELECT id,account,parvalue,operators,inprice,status,cstatus,bid,qdprice,addtime from o_flowtime where userid=:userid and orderid=:orderid limit 1) union all (SELECT id,account,parvalue,operators,inprice,status,cstatus,bid,qdprice,addtime from o_lifetime where userid=:userid and orderid=:orderid limit 1)", ['userid' => $inputData['userid'], 'orderid' => $inputData['orderid']])->getResult();
        if (!empty($order[0])) {
            $order = $order[0];
            if (!in_array($order['status'], [2,3])) $order['status'] = 1;
            return ['status' => 1000, 'tranid' => $order['id'],'account' => $order['account'],'amount' => $order['parvalue'], 'operator' => $order['operators'], 'payment' => $order['inprice'],'resultno' => $order['status'],'addtime' => $order['addtime']];
        }

        // 测试用户
        if (in_array($inputData['userid'], [13])) {
            throw new \Exception('提交订单信息不符合要求', 1);
            // $status = 4;
        }

        // 查询商户订单商品信息
        do {
            // if ($tables['priceTable'] == 'o_price_flow' || $tables['rebateTable'] == 'o_rebate_flow') {
            if ($tables['orderTable'] == 'o_flowtime') {
                $addFields = ',price';
            } else {
                $addFields = '';
            }

            // 针对Q币面值特殊处理
            if ($inputData['shoptype'] == 31) {
                $amount = 1;
            } else {
                $amount = $inputData['amount'];
            }

            // 查询密价表
            if ($inputData['shopid']) {
                $where = ' where shopid=:shopid and userid=:userid limit 1';
                $bindParams = ['shopid' => $inputData['shopid'], 'userid' => $inputData['userid']];
            } else {
                $where = ' where shoptype=:shoptype and province=:province and corp=:corp and amount=:amount and userid=:userid limit 1';
                $bindParams = ['shoptype' => $inputData['shoptype'], 'province' => $province, 'corp' => $corp, 'amount' => $amount, 'userid' => $inputData['userid']];
            }
            $sql = "SELECT shopid,discount as inprice,isopen,bid1,bid2,bid3,amount,province,corp,shoptype,precallback{$addFields} from {$tables['rebateTable']} ".$where;
            $priceResult = Db::query($sql, $bindParams)->getResult();
            if (!empty($priceResult)) {
                break;
            }

            // 查询价格表
            $selectFields = "shopid,inprice,isopen,bid1,bid2,amount,province,corp,shoptype";
            if ($user['oprice'] != 1) {
                $selectFields .= ',bid3,bid4';
            }
            if ($inputData['shopid']) {
                $where = ' where shopid=:shopid limit 1';
                $bindParams = ['shopid' => $inputData['shopid']];
            } else {
                $where = ' where shoptype=:shoptype and province=:province and corp=:corp and amount=:amount limit 1';
                $bindParams = ['shoptype' => $inputData['shoptype'], 'province' => $province, 'corp' => $corp, 'amount' => $amount];
            }
            $sql = "SELECT {$selectFields}{$addFields} from {$tables['priceTable']} ".$where;
            $priceResult = Db::query($sql, $bindParams)->getResult();
        } while (0);

        if (empty($priceResult) || empty($priceResult[0])) {
            throw new \Exception('不存在这个商品', 245);
        }
        $priceResult = $priceResult[0];
        if ($priceResult['isopen'] == 0) {
            throw new \Exception('该商品维护关闭', 245);
        }
        if (!in_array($inputData['userid'], array_merge($merchantConfig['DO_NOT_PAY_LIST'], $merchantConfig['CHARGE_SUCCESS_LIST'])) && bccomp($priceResult['inprice'], '0', 4) <= 0) {
            // 非特定渠道 价格为 0 则表示渠道维护
            throw new \Exception('该商品维护关闭', 245);
        }

        // 获取充值渠道
        $bid = empty($priceResult['bid1']) ? $priceResult['bid2'] : $priceResult['bid1'];
        if (empty($bid)) {
            $bid = empty($priceResult['bid3']) ? $priceResult['bid4'] : $priceResult['bid3'];
            if (empty($bid)) {
                throw new \Exception('该商品维护关闭', 245);
            }
        }

        $status = 0;
        if ($priceResult['isopen'] == 2) {
            $status = 4; // 蓄单
        }
        if ($priceResult['precallback'] == 1 && $cstatus == 0) {
            $cstatus = 4; // 判断是否预回调
        }

        // 针对指定商户且存在 inprice 传参时订单售价特别处理
        if (in_array($inputData['userid'], [1]) && !empty($inputData['inprice'])) {
            $priceResult['inprice'] = $inputData['inprice'];
        }

        // 针对Q币商品订单售价特别处理
        if ($priceResult['shoptype'] == 31 && $amount == 1) {
            $priceResult['inprice'] = bcmul($inputData['amount'], $priceResult['inprice'], 3);
        }

        // 创建订单 扣款
        Db::beginTransaction();

        // 订单插入
        // $sql = "INSERT into {$tables['orderTable']} (orderid,userid,shopid,shoptype,account,parvalue,operators,inprice,qdprice,status,bid,cstatus,rcvtime,addtime) values ()";
        $orderClass = 'App\\Models\\Entity\\'.$tables['orderEntity'];
        $order = new $orderClass;
        $order->setOrderid($inputData['orderid']);
        $order->setUserid($inputData['userid']);
        $order->setShopid($priceResult['shopid']);
        $order->setShoptype($priceResult['shoptype']);
        $order->setAccount($inputData['account']);
        $order->setParvalue($inputData['amount']);
        $order->setOperators($priceResult['province'].$priceResult['corp']);
        $order->setInprice($priceResult['inprice']);
        $order->setStatus($status);
        $order->setBid($bid);
        $order->setCstatus($cstatus);
        $order->setAddtime($now);
        $order->setRcvtime($now);
        if ($tables['orderTable'] == 'o_flowtime') {
            $order->setPrice($priceResult['price']);
        }

        $tranId = $order->save()->getResult();
        if (!$tranId) {
            Db::rollback();
            throw new \Exception('创建订单失败', 1);
        }

        // 判断是否需要先扣款
        if (!in_array($inputData['userid'], array_merge($merchantConfig['DO_NOT_PAY_LIST'], $merchantConfig['CHARGE_SUCCESS_LIST']))) {
            // 商户扣款
            $sql = "UPDATE m_userapi set balance = @balance := balance - {$priceResult['inprice']} where userid = {$inputData['userid']} and (balance + credit) >= {$priceResult['inprice']}";
            $updateResult = Db::query($sql)->getResult();
            if (!$updateResult) {
                Db::rollback();
                throw new \Exception('用户订单支付失败或余额不足', 1);
            }

            // 查询更新后余额
            // $balanceResult = Db::query("SELECT @balance as balance")->getResult();

            // 新增用户资金记录
            $sql = "INSERT into m_cashlist(userid,orderid,fundtype,payment,balance,payip) values({$inputData['userid']},:orderid,2,{$priceResult['inprice']},@balance,'{$ip}')";
            $cashId = Db::query($sql, ['orderid' => $inputData['orderid']])->getResult();
            if (!$cashId) {
                Db::rollback();
                throw new \Exception('添加资金记录失败', 1);
            }
        }

        Db::commit();
        // Db::rollback();

        if ($status == 0) {
            $result = Task::deliver('merchant', 'sendOrderAsync', [$tables['orderTable'], $tranId], Task::TYPE_ASYNC);
        }

        return ['status' => 1000, 'msg' => 'SUCCESS', 'resultno' => 0, 'tranid' => $tranId, 'account' => $inputData['account'], 'operator' => $priceResult['province'].$priceResult['corp'], 'amount' => $inputData['amount'], 'payment' => $priceResult['inprice'], 'addtime' => $now];
    }

    /**
     * 商户订单查询 v2018.7.17
     * @RequestMapping(route="search[/]")
     * @Middleware(MerchantSearchMiddleware::class)
     * @return array
     */
    public function search(Request $request): array
    {
        $inputData = $request->input();

        $ip = $request->getHeaderLine('X-Real-IP');

        $user = $this->validateIpAndSign($inputData, $ip, 'search');

        $tables = \Jpay\Helper\get_shop_table($inputData['shoptype']);
        if (empty($tables)) {
            throw new \Exception('shoptype取值不正确', 501);
        }

        $order = Db::query("SELECT id,account,parvalue,retvalue,inprice,status,cstatus,bid,qdprice from {$tables['orderTable']} where userid=:userid and orderid=:orderid limit 1", ['userid' => $inputData['userid'], 'orderid' => $inputData['orderid']])->getResult();
        if (empty($order)) {
            throw new \Exception('无此订单', 504);
        }
        $order = $order[0];

        // 预回调订单直接做充值成功处理
        if ($order['cstatus'] == 4 && $inputData['orderid'] != 4) $order['status'] = 2;
        if (!in_array($order['status'], [2,3])) $order['status'] = 2;

        $backData = ['status' => 1000, 'userid' => $inputData['userid'],'orderid' => $inputData['orderid'], 'tranid' => $order['id'],'mobile' => $order['account'],'amount' => $order['parvalue'],'payment' => $order['inprice'],'resultno' => $order['status']];

        $backQdpriceList = \config('BACK_QDPRICE_LIST');
        if (in_array($inputData['userid'], $backQdpriceList)) {
            $backData['qdprice'] = $order['qdprice'];
            $backData['bid'] = $order['bid'];
        }
        return $backData;
    }

    /**
     * 商户余额查询 v2018.7.9
     * @RequestMapping(route="balance[/]")
     * @return array
     */
    public function balance(Request $request): array
    {
        $inputData = $request->input();

        if (empty($inputData['userid']) || empty($inputData['vstr'])) {
            throw new \Exception('必要参数为空', 501);
        }

        if (!is_numeric($inputData['userid']) && !strpos($inputData['userid'], '.')) {
            throw new \Exception('参数取值不正确', 502);
        }

        $ip = $request->getHeaderLine('X-Real-IP');

        $user = $this->validateIpAndSign($inputData, $ip, 'balance');

        return ['status' => 1000, 'msg' => 'SUCCESS', 'balance' => $user['balance']];
    }

    /**
     * validateIpAndSign
     * ip 白名单验证与签名验证
     * @access private
     * @param array $inputData
     * @param string $ip
     * @param string $signSource
     * @return array
     */
    private function validateIpAndSign(array $inputData, string $ip, string $signSource): array
    {
        $user = MUserapi::findById($inputData['userid'])->getResult();
        if (empty($user)) {
            throw new \Exception('找不到这个用户ID', 201);
        }
        $user = $user->toArray();

        // IP 白名单验证
        if (!in_array($ip, explode(',', $user['ipwhite']))) {
            throw new \Exception('提交IP不在白名单中', 228);
        }

        // 判断加密方式 签名验证
        $signFieldsArr = [
            'submit' => ['userid','orderid','shoptype','account','amount','ordertime'],
            'search' => ['userid', 'orderid', 'shoptype'],
            'balance' => ['userid'],
        ];
        $signFields = $signFieldsArr[$signSource]; // 参与签名字段

        if (!filter_var(strtolower($inputData['vstr']), FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[0-9a-f]{32}$/')))) {
            throw new \Exception('签名错误', 228);
        }

        $data = array_intersect_key($inputData, array_flip($signFields));
        ksort($data);
        $sign = md5(urldecode(http_build_query($data)).'&key='.$user['userkey']);
        if ($sign != $inputData['vstr']) {
            throw new \Exception('签名错误', 228);
        }

        return $user;
    }

    /**
     * getShopTable
     * 根据 shoptype 获取相应的数据表
     * @return array
     */
    public function getShopTable(int $shopType): array
    {
        if ($shopType < 20) {
            $orderTable = 'o_realtime';
            $orderEntity = 'ORealtime';
            $priceTable = 'o_price';
            $priceEntity = 'OPrice';
            $rebateTable = 'o_rebate';
            $rebateEntity = 'ORebate';
        } elseif ($shopType < 30) {
            $orderTable = 'o_flowtime';
            $orderEntity = 'OFlowtime';
            $priceTable = 'o_price_flow';
            $priceEntity = 'OPriceFlow';
            $rebateTable = 'o_rebate_flow';
            $rebateEntity = 'ORebateFlow';
        } elseif ($shopType < 40) {
            $orderTable = 'o_lifetime';
            $orderEntity = 'oLifetime';
            $priceTable = 'o_price';
            $priceEntity = 'OPrice';
            $rebateTable = 'o_rebate';
            $rebateEntity = 'ORebate';
        } elseif ($shopType > 200) {
            $orderTable = 'o_flowtime';
            $orderEntity = 'OFlowtime';
            $priceTable = 'o_price_flow';
            $priceEntity = 'OPriceFlow';
            $rebateTable = 'o_rebate_flow';
            $rebateEntity = 'ORebateFlow';
        } else {
            return [];
        }
        return compact('orderTable', 'orderEntity', 'priceTable', 'priceEntity', 'rebateTable', 'rebateEntity');
    }
}
